package com.fand.persistent.support;

import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;

import com.fand.dto.PaginationDto;
import com.fand.persistent.builder.ModelBuilder;
import com.fand.template.support.TemplateSupport;
import com.fand.utils.PaginationUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * jdbc dao
 * 
 * @author haitao.yao
 * 
 */
public class JdbcDaoSupport implements DaoSupport {
	/**
	 * namedParameterJdbcDaoSupport
	 */
	protected RouterNamedParameterJdbcTemplateSupport routerNamedParameterJdbcTemplateSupport;

	/**
	 * 模板支持
	 */
	protected TemplateSupport templateSupport;

	@Override
	public String builderSql(final String sqlId, final Map<String, Object> model) {
		final String sql = this.templateSupport.processTemplateIntoString(sqlId, model);

		return sql;
	}

	@Override
	public PaginationDto<Map<String, Object>> paginationForMapList(final String selectForObjectSqlId,
			final String selectForMapListSqlId, final int paginationNo, final int paginationSize, Map<String, Object> model) {
		final int totalSize = this.selectForObject(Integer.class, selectForObjectSqlId, null, model);

		final PaginationDto<Map<String, Object>> pagination = PaginationUtils.newPagination(paginationNo, paginationSize, totalSize);

		List<Map<String, Object>> dataList;

		if (totalSize < 1) {
			dataList = Lists.newArrayList();
		} else {
			if (totalSize < pagination.getBeginRowNum()) {
				dataList = Lists.newArrayList();
			} else {
				if (model == null) {
					model = Maps.newHashMap();
				}

				model.put("BEGIN__ROW__NUM", pagination.getBeginRowNum());

				model.put("END__ROW__NUM", pagination.getEndRowNum());

				dataList = this.selectForMapList(selectForMapListSqlId, model);
			}
		}

		pagination.setDataList(dataList);

		return pagination;
	}

	@Override
	public <T> PaginationDto<T> paginationForMappedObjectList(final Class<T> mappedClass, final String selectForObjectSqlId,
			final String selectForMappedObjectListSqlId, final int paginationNo, final int paginationSize, Map<String, Object> model) {
		final int totalSize = this.selectForObject(Integer.class, selectForObjectSqlId, null, model);

		final PaginationDto<T> pagination = PaginationUtils.newPagination(paginationNo, paginationSize, totalSize);

		List<T> dataList;

		if (totalSize < 1) {
			dataList = Lists.newArrayList();
		} else {
			if (totalSize < pagination.getBeginRowNum()) {
				dataList = Lists.newArrayList();
			} else {
				if (model == null) {
					model = Maps.newHashMap();
				}

				model.put("BEGIN__ROW__NUM", pagination.getBeginRowNum());

				model.put("END__ROW__NUM", pagination.getEndRowNum());

				dataList = this.selectForMappedObjectList(mappedClass, selectForMappedObjectListSqlId, model);
			}
		}

		pagination.setDataList(dataList);

		return pagination;
	}

	@Override
	public Map<String, Object> selectForMap(final String sqlId, final Map<String, Object> model) {
		final String sql = this.builderSql(sqlId, model);

		return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).queryForMap(sql, model);
	}

	@Override
	public List<Map<String, Object>> selectForMapList(final String sqlId, final Map<String, Object> model) {
		final String sql = this.builderSql(sqlId, model);

		return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).queryForList(sql, model);
	}

	@Override
	public <T> T selectForMappedObject(final Class<T> mappedClass, final String sqlId, final Map<String, Object> model) {
		final String sql = this.builderSql(sqlId, model);

		try {
			return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).queryForObject(sql, model,
					ParameterizedBeanPropertyRowMapper.newInstance(mappedClass));
		} catch (final EmptyResultDataAccessException e) {
			return null;
		}
	}

	@Override
	public <T> List<T> selectForMappedObjectList(final Class<T> mappedClass, final String sqlId, final Map<String, Object> model) {
		final String sql = this.builderSql(sqlId, model);

		return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).query(sql, model,
				ParameterizedBeanPropertyRowMapper.newInstance(mappedClass));
	}

	@Override
	public <T> T selectForObject(final Class<T> requiredType, final String sqlId, final String objectId, Map<String, Object> model) {
		if (StringUtils.isNotBlank(objectId)) {
			if (model == null) {
				model = Maps.newHashMap();
			}

			model.put(ModelBuilder.OBJECT_ID, objectId);
		}

		final String sql = this.builderSql(sqlId, model);

		return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).queryForObject(sql, model,
				requiredType);
	}

	@Override
	public <T> List<T> selectForObjectList(final Class<T> elementType, final String sqlId, final String objectId,
			Map<String, Object> model) {
		if (StringUtils.isNotBlank(objectId)) {
			if (model == null) {
				model = Maps.newHashMap();
			}

			model.put(ModelBuilder.OBJECT_ID, objectId);
		}

		final String sql = this.builderSql(sqlId, model);

		return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).queryForList(sql, model,
				elementType);
	}

	public void setRouterNamedParameterJdbcTemplateSupport(
			final RouterNamedParameterJdbcTemplateSupport routerNamedParameterJdbcTemplateSupport) {
		this.routerNamedParameterJdbcTemplateSupport = routerNamedParameterJdbcTemplateSupport;
	}

	public void setTemplateSupport(final TemplateSupport templateSupport) {
		this.templateSupport = templateSupport;
	}

	@Override
	public int update(final String sqlId, final List<Map<String, Object>> modelList) {
		if (CollectionUtils.isEmpty(modelList)) {
			return 0;
		}

		int rowCount = 0;

		for (final Map<String, Object> model : modelList) {
			rowCount += this.update(sqlId, model);
		}

		return rowCount;
	}

	@Override
	public int update(final String sqlId, final Map<String, Object> model) {
		final String sql = this.builderSql(sqlId, model);

		return this.routerNamedParameterJdbcTemplateSupport.getNamedParameterJdbcTemplate(sqlId, model).update(sql, model);
	}
}
